//! @author Adam Emil Skoog
//! @date   2011-12-25

#ifndef KEDJA_POINT_H_
	#define KEDJA_POINT_H_

	namespace kedja
	 {
		template<class T> class Size;

		/**
		 * A two-dimensional coördinate.
		 */
		template<class T> class Point
		 {
			public:
				// Declare functions.
				Point(const T &x = T(0),const T &y = T(0));
				Point(const Size<T> &);
				Point<T> &operator=(const Size<T> &);
				T &x();
				const T &x() const;
				T &y();
				const T &y() const;

			private:
				// Properties.
				T xValue,
				  yValue;
		 };

		/**
		 * A two-dimensional size.
		 */
		template<class T> class Size
		 {
			public:
				// Declare functions.
				Size(const T &width = T(0),const T &height = T(0));
				Size(const Point<T> &);
				Size<T> &operator=(const Point<T> &);
				T &width();
				const T &width() const;
				T &height();
				const T &height() const;

			private:
				// Properties.
				T widthValue,
				  heightValue;
		 };

		/**
		 * Constructor.
		 *
		 * @param x The horizontal value to set. Defaults to 0 if omitted.
		 * @param y The vertical value to set. Defaults to 0 if omitted.
		 */
		template<class T> Point<T>::Point(const T &x,const T &y)
		:
		xValue(x),
		yValue(y)
		 {
		 }

		/**
		 * Constructor initialising the point with the values of a size object.
		 *
		 * @param other The size object to copy the values from.
		 */
		template<class T> Point<T>::Point(const Size<T> &other)
		:
		xValue(other.width()),
		yValue(other.height())
		 {
		 }

		/**
		 * Overloaded assignment operator to set the values to those of a size object.
		 *
		 * @param other The size object to copy the values from.
		 * @return The modified point object.
		 */
		template<class T> Point<T> &Point<T>::operator=(const Size<T> &other)
		 {
			xValue = other.width();
			yValue = other.height();
			return *this;
		 }

		/**
		 * Returns a variable reference to the horizontal value.
		 *
		 * @return A variable reference to the x property.
		 */
		template<class T> T &Point<T>::x()
		 {
			return xValue;
		 }

		/**
		 * Returns a constant reference to the horizontal value.
		 *
		 * @return A constant reference to the x property.
		 */
		template<class T> const T &Point<T>::x() const
		 {
			return xValue;
		 }

		/**
		 * Returns a variable reference to the vertical value.
		 *
		 * @return A variable reference to the y property.
		 */
		template<class T> T &Point<T>::y()
		 {
			return yValue;
		 }

		/**
		 * Returns a constant reference to the vertical value.
		 *
		 * @return A constant reference to the y property.
		 */
		template<class T> const T &Point<T>::y() const
		 {
			return yValue;
		 }

		/**
		 * Constructor.
		 *
		 * @param width The width to set. Defaults to 0 if omitted.
		 * @param height The height to set. Defaults to 0 if omitted.
		 */
		template<class T> Size<T>::Size(const T &width,const T &height)
		:
		widthValue (width),
		heightValue(height)
		 {
		 }

		/**
		 * Constructor initialising the size with the values of a point object.
		 *
		 * @param other The point object to copy the values from.
		 */
		template<class T> Size<T>::Size(const Point<T> &other)
		:
		widthValue (other.x()),
		heightValue(other.y())
		 {
		 }

		/**
		 * Overloaded assignment operator to set the values to those of a point object.
		 *
		 * @param other The point object to copy the values from.
		 * @return The modified size object.
		 */
		template<class T> Size<T> &Size<T>::operator=(const Point<T> &other)
		 {
			widthValue  = other.x();
			heightValue = other.y();
			return *this;
		 }

		/**
		 * Returns a variable reference to the width.
		 *
		 * @return A variable reference to the width property.
		 */
		template<class T> T &Size<T>::width()
		 {
			return widthValue;
		 }

		/**
		 * Returns a constant reference to the width.
		 *
		 * @return A constant reference to the width property.
		 */
		template<class T> const T &Size<T>::width() const
		 {
			return widthValue;
		 }

		/**
		 * Returns a variable reference to the height.
		 *
		 * @return A variable reference to the height property.
		 */
		template<class T> T &Size<T>::height()
		 {
			return heightValue;
		 }

		/**
		 * Returns a constant reference to the height.
		 *
		 * @return A constant reference to the height property.
		 */
		template<class T> const T &Size<T>::height() const
		 {
			return heightValue;
		 }
	 }
#endif
